import { isNil, omit } from 'lodash';
import { DeleteDto, DeletePrimaryObjDto, DeleteStrPrimaryDto, ResponseJson, SqlQueryDto, UpdateDto } from '@/common/type/app.dto';
import { ResponseCode } from '@/common/type/enum';
import { Injectable } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource, DeepPartial, DeleteResult, EntityManager, EntityTarget, ObjectLiteral, SelectQueryBuilder, QueryRunner } from 'typeorm';
import { countQueryBuilder, relationQueryBuilder, selectAndTakeQueryBuilder, whereAndOrderQueryBuilder } from '@/common/tool/sqlbuilder';

type queryOption = {
    sum: boolean
}


@Injectable()
export class CrudService {
    constructor(@InjectDataSource() private datasource: DataSource) {}

    async create<T extends ObjectLiteral, K>(entity: EntityTarget<T>, dto: K, m?: EntityManager): Promise<ResponseJson<T, null>> {
        const manager = m ?? this.datasource.manager;
        const obj = manager.create<T>(
            entity,
            dto as DeepPartial<T>,
        );
        const r = await manager.save<T>(obj);
        
        return {
            code: ResponseCode.SuccessWithInfo,
            msg: ['添加成功'],
            obj: r,
        };
    }
    async update<T extends ObjectLiteral>(entity: EntityTarget<T>, dto: UpdateDto, primaryObj: any = null, m?: EntityManager): Promise<ResponseJson<null, null>> {
        
        
        const where = primaryObj ?? {id: dto['id']};
        const manager = m ?? this.datasource.manager;
        try {
            const result = await manager.update<T>(
                entity,
                where,
                // omit(omit(dto, ['id', 'primary_cod']), Object.keys(where)),
                omit(dto, ['id', 'primary_cod']),
            );
           
            return {
                code:
                    result.affected === 1
                        ? ResponseCode.SuccessNoMsg
                        : ResponseCode.FailWithMsg,
                msg: result.affected === 1 ? [] : ['修改失败'],
            };
        }catch(error) {
            console.log(error);
            throw error;
        }
        
    }
    async deleteStrIds<T extends ObjectLiteral>(entity: EntityTarget<T>, dto: DeleteStrPrimaryDto, where?: any): Promise<ResponseJson> {

        let r: DeleteResult;
        if (isNil(where)) {
            r = await this.datasource.manager.getRepository(entity).delete(dto.ids);    
        } else {
            r = await this.datasource.manager.getRepository(entity).delete(where);    
        }
        if (r) {
            return {
                code: ResponseCode.SuccessWithSuc,
                msg: [`删除${r.affected}条记录`],
            };
        } else {
            return {
                code: ResponseCode.FailWithMsg,
                msg: [`删除失败`],
            };
        }
    }
    async deleteObjIds<T extends ObjectLiteral>(entity: EntityTarget<T>, dto: DeletePrimaryObjDto): Promise<ResponseJson> {
        const queryRunner = this.datasource.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            for (let index = 0; index < dto.ids.length; index++) {
                const element = dto.ids[index];
                await queryRunner.manager.getRepository(entity).delete(element);
            }
           
            await queryRunner.commitTransaction();
            return {
                code: ResponseCode.SuccessWithInfo,
                msg: [`删除${dto.ids.length}条记录`],
            };
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
    async delete<T extends ObjectLiteral>(entity: EntityTarget<T>, dto: DeleteDto, q?: QueryRunner): Promise<ResponseJson> {
        let r: DeleteResult;
        const queryRunner = q ?? this.datasource.createQueryRunner();
        if (dto.ids.length === 1) {
            r = await queryRunner.manager
                .createQueryBuilder()
                .delete()
                .from<T>(entity)
                .where('id = :id', { id: dto.ids[0] })
                .execute();
        } else {
            r = await queryRunner.manager
                .createQueryBuilder()
                .delete()
                .from<T>(entity)
                .where('id in (:...ids)', { ids: dto.ids })
                .execute();
        }
        // await queryRunner.connect();
        // await queryRunner.startTransaction();
        /* try {
            if (dto.ids.length === 1) {
                r = await queryRunner.manager
                    .createQueryBuilder()
                    .delete()
                    .from<T>(entity)
                    .where('id = :id', { id: dto.ids[0] })
                    .execute();
            } else {
                r = await queryRunner.manager
                    .createQueryBuilder()
                    .delete()
                    .from<T>(entity)
                    .where('id in (:...ids)', { ids: dto.ids })
                    .execute();
            }
            // await queryRunner.commitTransaction();
        } catch (err) {
            // await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            // await queryRunner.release();
        } */
        if (r) {
            return {
                code: ResponseCode.SuccessWithSuc,
                msg: [`删除${r.affected}条记录`],
            };
        } else {
            return {
                code: ResponseCode.FailWithMsg,
                msg: [`删除失败`],
            };
        }
    }
    async query<T extends ObjectLiteral>(entity: EntityTarget<T>, query: SqlQueryDto, option?: queryOption): Promise<ResponseJson<T[], number | undefined>> {
        const op = option ?? {
            sum: true,
        };
        const table_name = await this.datasource.getMetadata(entity).tableMetadataArgs.name;
        
        const queryBuilder = this.datasource.createQueryBuilder();
        whereAndOrderQueryBuilder({ queryBuilder, query, table_name });
        selectAndTakeQueryBuilder({ queryBuilder, query, table_name });
        queryBuilder.from<T>(entity, table_name);
        relationQueryBuilder({ queryBuilder, query });
//         console.log('get sql', queryBuilder);
        
        if (op.sum) {
            const r = await queryBuilder
            .getManyAndCount();
            return {
                code: ResponseCode.SuccessNoMsg,
                obj: r[0],
                ext: r[1]
            };
        } else {
            const r = await queryBuilder
            .getMany();
            return {
                code: ResponseCode.SuccessNoMsg,
                obj: r,
            };
        }
    }
    
    /* async getQueryBuilder<T extends ObjectLiteral>(entity: EntityTarget<T>, query: SqlQueryDto): Promise<SelectQueryBuilder<T>> {
        // console.log(entity);
        const table_name = await this.datasource.getMetadata(entity).tableMetadataArgs.name;
        
        const queryBuilder = this.datasource.createQueryBuilder();
        whereAndOrderQueryBuilder({ queryBuilder, query });
        selectAndTakeQueryBuilder({ queryBuilder, query, table_name });
        queryBuilder.from<T>(entity, table_name);
        return queryBuilder;
    }   */
}
